﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

using alib;
using alib.Debugging;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// Note that this doesn't mean that the type necessarily has no appropriate features, just that none of them
	/// are constrained in this instance. This object handles either situation properly.
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public unsafe sealed class EmptyFeatureStructureTfs : Tfs
	{
		public EmptyFeatureStructureTfs(IRtParent parent, Type t)
			: base(parent, t, t.ftm.r_none, Flags.None)
		{
			Debug.Assert(c_corefs == 0);
			flags = Tfs.Flags.Expanded;
			if ((t.m_flags & Type.Flags.TopType) != 0)
			{
				Debug.Assert(t._id == configuration.TypesConfig.TopId && !t.HasAppropriateFeatures);
				this._top_edge = default(Edge);
			}
			else
				this._top_edge = tu.CreateEdge(t, t.HasAppropriateFeatures ? 1 : 0, false);
		}

		public override bool TryGetEdge(int i_feat, int mark, out Edge e)
		{
			e = default(Edge);
			return false;
		}
		public override Edge.Flag TryGetFlagsMark(int i_feat, int mark, out int m)
		{
			m = 0;
			return 0;
		}

		public override int EdgeCount { get { return 0; } }
		public override int SlotCount { get { return 0; } }

		public override SlotRefArray SlotRefArray
		{
			get { return new SlotRefArray(this, new[] { 0 }); }
		}

		public override unsafe void GetIndexData(int ix1, arr_tfs_entry* pate)
		{
			Debug.Assert(ix1 == 0);
			*pate = default(arr_tfs_entry);
			pate->e = _top_edge;
#if false
			int grm_idx = 0;
			if (g != null)
				grm_idx = g.grm_idx;
			pate->tgrm = new TaggedRelMode(grm_idx, RelMode.None);
#endif
		}

		public override unsafe int GetEdgeIndex(int i_feat, int mark, Edge* pe)
		{
			Debug.Assert(mark == _top_edge.Mark);
			return 0;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class DummyTfs : Tfs
	{
		public DummyTfs(IRtParent parent) : base(parent, parent, default(Restrictor), Flags.None) { }
		public sealed override bool TryGetEdge(int i_feat, int mark, out Edge e) { throw not.impl; }
		public sealed override Edge.Flag TryGetFlagsMark(int i_feat, int mark, out int m) { throw not.impl; }
		public sealed override int EdgeCount { get { throw not.impl; } }
		public sealed override unsafe void GetIndexData(int ix1, arr_tfs_entry* pate) { throw not.valid; }
		public sealed override unsafe int GetEdgeIndex(int i_feat, int mark, Edge* pe) { throw not.valid; }
		public sealed override SlotRefArray SlotRefArray { get { throw not.valid; } }
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// you cannot create instances of this one. There's just the one static instance acrossall grammars.
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class NullTfs : DummyTfs
	{
		public NullTfs(IRtParent parent) : base(parent) { }
		public override String ToString() { return "(NullTfs global instance)"; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// you can create your own instances of this one (i.e. for concurrency placeholders that are reference-distinct)
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	
	public sealed class BusyTfs : DummyTfs
	{
		public BusyTfs(IRtParent parent) : base(parent) { }
	};
}